<template>
  <el-container>
    <el-header style="height: auto">
      <el-form :model="queryInfo" ref="queryForm" size="small" :inline="true">
        <el-form-item prop="menuName">
          <el-input v-model="queryInfo.menuName" @keyup.enter.native="$event.target.blur"
                    placeholder="搜索菜单名"
                    prefix-icon="el-icon-search"></el-input>
        </el-form-item>
        <el-form-item prop="status">
          <el-select clearable v-model="queryInfo.status" placeholder="请选择菜单状态" style="margin-left: 5px">
            <el-option
              v-for="item in status"
              :key="item.type"
              :label="item.info"
              :value="item.type">
            </el-option>
          </el-select>
        </el-form-item>
        <el-form-item prop="menuType">
          <el-select clearable v-model="queryInfo.menuType" placeholder="请选择菜单类型" style="margin-left: 5px">
            <el-option
              v-for="item in menuType"
              :key="item.type"
              :label="item.info"
              :value="item.type">
            </el-option>
          </el-select>
        </el-form-item>
        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
        <el-button type="primary" style="margin-left: 5px" icon="el-icon-search" @click="getMenuInfo"
                   v-hasPermi="['system:menu:query']">查询
        </el-button>
        <el-button type="primary" style="margin-left: 5px" icon="el-icon-plus" @click="showAddDialog"
                   v-hasPermi="['system:menu:add']">添加
        </el-button>
      </el-form>
    </el-header>

    <el-main>
      <el-button type="info" plain icon="el-icon-sort" size="mini" @click="toggleExpandAll">展开/折叠</el-button>
      <!--操作的下拉框-->
      <el-select @change="selectChange" clearable v-if="selectedInTable.length !== 0" v-model="selected"
                 :placeholder="'已选择' + selectedInTable.length + '项'" style="margin-bottom: 25px;">

        <el-option value="on" v-hasPermi="['system:menu:statusOn']">
          <span style="float: left">启用</span>
          <span style="float: right; color: #8492a6; font-size: 13px">on</span>
        </el-option>
        <el-option value="off" v-hasPermi="['system:menu:statusOff']">
          <span style="float: left">禁用</span>
          <span style="float: right; color: #8492a6; font-size: 13px">off</span>
        </el-option>
        <el-option value="delete" v-hasPermi="['system:menu:remove']">
          <span style="float: left">删除</span>
          <span style="float: right; color: #8492a6; font-size: 13px">delete</span>
        </el-option>

      </el-select>

      <el-table
        v-hasPermi="['system:menu:query']"
        v-if="refreshTable"
        v-loading="loading"
        :data="menuInfo"
        :row-key="menuRowKeys"
        :default-expand-all="isExpandAll"
        :select-on-indeterminate="true"
        @select="select"
        @select-all="selectAll"
        @selection-change="handleSelectionChange"
        ref="menuTable"
        :tree-props="{children: 'children', hasChildren: 'hasChildren'}">
        <el-table-column type="selection" width="55"></el-table-column>
        <el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160">
        </el-table-column>
        <el-table-column prop="icon" label="图标" align="center" width="100">
          <template slot-scope="scope">
            <i :class="scope.row.icon"></i>
          </template>
        </el-table-column>
        <el-table-column prop="orderNum" label="排序" width="60"></el-table-column>
        <el-table-column prop="menuPerms" label="菜单标识" :show-overflow-tooltip="true"></el-table-column>
        <el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true"></el-table-column>
        <el-table-column label="创建时间" align="center" prop="createTime">
          <template slot-scope="scope">
            <span>{{ scope.row.createTime }}</span>
          </template>
        </el-table-column>
        <el-table-column label="更新时间" align="center" prop="updateTime">
          <template slot-scope="scope">
            <el-popover trigger="hover" placement="top">
              <p>{{ scope.row.remark }}</p>
              <div slot="reference" class="name-wrapper">
                <el-tag size="medium">{{ scope.row.updateTime }}</el-tag>
              </div>
            </el-popover>
          </template>
        </el-table-column>
        <el-table-column prop="status" label="状态" align="center" width="80">
          <template slot-scope="scope">
            <i v-if="scope.row.status == 0" class="el-icon-check"
               style="font-size: 20px; background: #E8F4FF; color: #1890FF"></i>
            <i v-else class="el-icon-close" style="font-size: 20px; background: #FFEDED; color: #FF4949"></i>
          </template>
        </el-table-column>
        <el-table-column
          fixed="right"
          align="center"
          label="操作">
          <template slot-scope="scope">
            <el-button @click="showUpdateDialog(scope.row)" type="text" size="small" v-hasPermi="['system:menu:edit']">
              修改
            </el-button>
            <el-button @click="showDeleteMenuDialog(scope.row)" type="text" size="small"
                       v-hasPermi="['system:menu:remove']">删除
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-main>

    <el-dialog title="添加菜单" :visible.sync="addTableVisible" width="30%" @close="resetAddForm"
               :close-on-click-modal="false"
               center>

      <el-form :model="addForm" :rules="addFormRules" ref="addForm">

        <el-form-item label="菜单类型" prop="menuType">
          <el-radio-group @change="menuTypeChange" v-model="addForm.menuType">
            <el-radio label=0>目录</el-radio>
            <el-radio label=1>菜单</el-radio>
            <el-radio label=2>功能</el-radio>
          </el-radio-group>
        </el-form-item>

        <el-form-item label="菜单名称" prop="menuName">
          <el-input v-model="addForm.menuName"></el-input>
        </el-form-item>

        <el-form-item label="上级菜单" prop="parentId">
          <treeselect
            v-model="addForm.parentId"
            :options="menuOptions"
            :normalizer="normalizer"
            :show-count="true"
            :flat="true"
            placeholder="选择上级菜单"
          />
        </el-form-item>

        <el-form-item label="菜单状态" prop="status">
          <el-select v-model="addForm.status" placeholder="请选择菜单状态">
            <el-option label="有效" value="0"></el-option>
            <el-option label="无效" value="1"></el-option>
          </el-select>
        </el-form-item>

        <el-form-item label="备注" prop="remark">
          <el-input v-model="addForm.remark"></el-input>
        </el-form-item>

        <el-form-item label="排序号" prop="orderNum">
          <el-input-number v-model="addForm.orderNum" controls-position="right" :min="0"/>
        </el-form-item>

        <e-icon-picker style="margin-bottom: 10px" v-if="addForm.menuType == '0' || addForm.menuType == '1'"
                       v-model="addForm.icon"/>

        <el-form-item prop="menuUrl" v-if="addForm.menuType == '1'">
          <el-tooltip content="访问的路径，为网址末尾的字符，如：`index`" placement="top">
            <i class="el-icon-question"></i>
          </el-tooltip>
          访问地址
          <el-input v-model="addForm.menuUrl" placeholder="请输入组件地址"/>
        </el-form-item>

        <el-form-item prop="component" v-if="addForm.menuType == '1'">
          <el-tooltip content="访问的组件在系统文件夹下的路径，如：`components/UserManage`" placement="top">
            <i class="el-icon-question"></i>
          </el-tooltip>
          组件路径
          <el-input v-model="addForm.component" placeholder="请输入组件地址"/>
        </el-form-item>

        <el-form-item prop="menuPerms" v-if="addForm.menuType == '2'">
          <el-tooltip content="控制器中定义的菜单标识，如：system:user:list" placement="top">
            <i class="el-icon-question"></i>
          </el-tooltip>
          菜单标识
          <el-input v-model="addForm.menuPerms" placeholder="请输入权限标识" maxlength="100"/>
        </el-form-item>
      </el-form>

      <div slot="footer" class="dialog-footer">
        <el-button @click="addTableVisible = false">取 消</el-button>
        <el-button type="primary" @click="addMenu">确 定</el-button>
      </div>
    </el-dialog>

    <el-dialog title="修改菜单" :visible.sync="updateTableVisible" width="30%" :close-on-click-modal="false"
               @close="resetUpdateForm"
               center>

      <el-form :model="updateForm" :rules="addFormRules" ref="updateForm">

        <el-form-item label="菜单类型" prop="menuType">
          <el-radio-group disabled v-model="updateForm.menuType">
            <el-radio label=0>目录</el-radio>
            <el-radio label=1>菜单</el-radio>
            <el-radio label=2>功能</el-radio>
          </el-radio-group>
        </el-form-item>

        <el-form-item label="菜单名称" prop="menuName">
          <el-input v-model="updateForm.menuName"></el-input>
        </el-form-item>

        <el-form-item label="上级菜单" prop="parentId">
          <treeselect
            v-model="updateForm.parentId"
            :options="menuOptions"
            :normalizer="normalizer"
            :show-count="true"
            :flat="true"
            placeholder="选择上级菜单"
          />
        </el-form-item>

        <el-form-item label="菜单状态" prop="status">
          <el-select v-model="updateForm.status" placeholder="请选择菜单状态">
            <el-option label="有效" value="0"></el-option>
            <el-option label="无效" value="1"></el-option>
          </el-select>
        </el-form-item>

        <el-form-item label="备注" prop="remark">
          <el-input v-model="updateForm.remark"></el-input>
        </el-form-item>

        <el-form-item label="排序号" prop="orderNum">
          <el-input-number v-model="updateForm.orderNum" controls-position="right" :min="0"/>
        </el-form-item>

        <e-icon-picker style="margin-bottom: 10px" v-if="updateForm.menuType == '0' || updateForm.menuType == '1'"
                       v-model="updateForm.icon"/>

        <el-form-item prop="menuUrl" v-if="updateForm.menuType == '1'">
          <el-tooltip content="访问的路径，为网址末尾的字符，如：`index`" placement="top">
            <i class="el-icon-question"></i>
          </el-tooltip>
          访问地址
          <el-input v-model="updateForm.menuUrl" placeholder="请输入组件地址"/>
        </el-form-item>

        <el-form-item prop="component" v-if="updateForm.menuType == '1'">
          <el-tooltip content="访问的组件在系统文件夹下的路径，如：`components/UserManage`" placement="top">
            <i class="el-icon-question"></i>
          </el-tooltip>
          组件路径
          <el-input v-model="updateForm.component" placeholder="请输入组件地址"/>
        </el-form-item>

        <el-form-item v-if="updateForm.menuType == '2'">
          <el-tooltip content="控制器中定义的菜单标识，如：system:user:list" placement="top">
            <i class="el-icon-question"></i>
          </el-tooltip>
          菜单标识
          <el-input v-model="updateForm.menuPerms" placeholder="请输入权限标识" maxlength="100"/>
        </el-form-item>
      </el-form>

      <div slot="footer" class="dialog-footer">
        <el-button @click="updateTableVisible = false">取 消</el-button>
        <el-button type="primary" @click="updateMenu">确 定</el-button>
      </div>
    </el-dialog>
  </el-container>
</template>

<script>
import {handleTree} from "@/plugins/handleTree";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";

export default {
  name: "MenuManage",
  components: {Treeselect},
  created() {
    this.getMenuInfo()
  },
  data() {
    return {
      //查询菜单的参数
      queryInfo: {
        'menuName': '',
        'status': '',
        'menuType': '',
      },
      //角色状态查询下拉框信息
      status: [
        {
          info: '全部',
          type: ''
        },
        {
          info: '有效',
          type: 0
        },
        {
          info: '无效',
          type: 1
        }
      ],
      menuType: [
        {
          info: '目录',
          type: 0
        },
        {
          info: '菜单',
          type: 1
        },
        {
          info: '功能',
          type: 2
        }
      ],
      //表格信息加载
      loading: true,
      // 菜单表格树数据
      menuList: [],
      // 是否展开，默认全部折叠
      isExpandAll: false,
      menuInfo: [],
      //被选择的表格中的行数据
      selectedInTable: [],
      // 重新渲染表格状态
      refreshTable: true,
      //下拉框所选择的数据
      selected: '',
      addTableVisible: false,
      updateTableVisible: false,
      //添加菜单的表单信息
      addForm: {
        'menuType': '0',
        'menuName': '',
        'parentId': 0,
        'status': '0',
        'remark': '',
        'orderNum': '',
        'icon': '',
        'menuUrl': '',
        'component': '',
        'menuPerms': ''
      },
      //修改菜单的表单信息
      updateForm: {
        'menuType': '0',
        'menuName': '',
        'parentId': 0,
        'status': '0',
        'remark': '',
        'orderNum': '',
        'icon': '',
        'menuUrl': '',
        'component': '',
        'menuPerms': ''
      },
      // 菜单树选项
      menuOptions: [],
      //添加用户表单的验证规则
      addFormRules: {
        menuName: [
          {
            required: true,
            message: '菜单名称必填',
            trigger: 'blur'
          },
          {
            max: 20,
            message: '菜单名称不能超过20个字符',
            trigger: 'blur'
          }
        ],
        remark: [
          {
            max: 500,
            message: '格式错误，长度应小于500',
            trigger: 'blur'
          }
        ],
        menuUrl: [
          {
            required: true,
            message: '访问路径必填',
            trigger: 'blur'
          }
        ],
        menuPerms: [
          {
            required: true,
            message: '菜单标识必填',
            trigger: 'blur'
          }
        ]
      },
    }
  },
  methods: {
    //获取菜单树
    getMenuInfo() {
      this.loading = true
      this.$http.get(this.API.getMenuByQuInfo, {params: this.queryInfo}).then((resp) => {
        if (resp.data.code === 200) {
          this.menuInfo = handleTree(resp.data.data.menus, "menuId");
          this.loading = false;
        } else {
          this.$notify({
            title: 'Tips',
            message: '获取信息失败',
            type: 'error',
            duration: 2000
          })
        }
      })
    },
    //重置搜索条件表单
    resetQuery() {
      this.$refs['queryForm'].resetFields()
      this.getMenuInfo()
    },
    menuRowKeys(row) {
      return row.menuId
    },
    /** 展开/折叠操作 */
    toggleExpandAll() {
      this.refreshTable = false;
      this.isExpandAll = !this.isExpandAll;
      this.$nextTick(() => {
        this.refreshTable = true;
      });
    },
    setChildren(children, type) {
      // 编辑多个子层级
      children.map(j => {
        this.toggleSelection(j, type)
        if (j.children) {
          this.setChildren(j.children, type)
        }
      })
    },
    // 选中父节点时，子节点一起选中取消
    select(selection, row) {
      const hasSelect = selection.some(el => {
        return row.menuId === el.menuId
      })
      if (hasSelect) {
        if (row.children) {
          // 解决子组件没有被勾选到
          this.setChildren(row.children, true)
        }
      } else {
        if (row.children) {
          this.setChildren(row.children, false)
        }
        if (row.parentId) {
          this.parentNotSelect(this.menuInfo, row.parentId)
        }
      }
    },
    parentNotSelect(data, index) {
      data.forEach(item => {
        if (item.menuId == index) {
          this.toggleSelection(item, false)
          return
        }
        if (item.children) {
          this.parentNotSelect(item.children, index)
        }
      })
    },
    toggleSelection(row, select) {
      if (row) {
        this.$nextTick(() => {
          this.$refs.menuTable &&
          this.$refs.menuTable.toggleRowSelection(row, select)
        })
      }
    },
    // 选择全部
    selectAll(selection) {
      // tabledata第一层只要有在selection里面就是全选
      const isSelect = selection.some(el => {
        const tableDataIds = this.menuInfo.map(j => j.menuId)
        return tableDataIds.includes(el.menuId)
      })
      // tableDate第一层只要有不在selection里面就是全不选
      const isCancel = !this.menuInfo.every(el => {
        const selectIds = selection.map(j => j.menuId)
        return selectIds.includes(el.menuId)
      })
      if (isSelect) {
        selection.map(el => {
          if (el.children) {
            // 解决子组件没有被勾选到
            this.setChildren(el.children, true)
          }
        })
      }
      if (isCancel) {
        this.menuInfo.map(el => {
          if (el.children) {
            // 解决子组件没有被勾选到
            this.setChildren(el.children, false)
          }
        })
      }
    },
    //表格某一行被选中
    handleSelectionChange(val) {
      this.selectedInTable = val
    },
    //功能下拉框被选择
    selectChange(val) {
      let tipInfo = ''
      if (val === 'on') {
        tipInfo = '是否继续启用所选用户?'
      } else if (val === 'off') {
        tipInfo = '是否继续禁用所选用户?'
      } else if (val === 'delete') {
        tipInfo = '此操作将永久删除所选用户, 是否继续?'
      }
      this.$confirm(tipInfo, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        //清空上一次的操作
        this.selected = ''
        //表格中所选中的用户的id
        let menuIds = []
        this.selectedInTable.map(item => {
          menuIds.push(item.menuId)
        })
        if (val === 'on') {//状态设置为有效
          this.$http.get(this.API.handleMenu + '/' + 1, {params: {'menuIds': menuIds.join(',')}}).then((resp) => {
            if (resp.data.code === 200) {
              //删除成功后,回调更新用户数据
              this.getMenuInfo()
              this.$notify({
                title: 'Tips',
                message: '操作成功',
                type: 'success',
                duration: 2000
              })
            } else {
              this.$notify({
                title: 'Tips',
                message: '操作失败',
                type: 'error',
                duration: 2000
              })
            }
          })
        } else if (val === 'off') {//禁用用户
          this.$http.get(this.API.handleMenu + '/' + 2, {params: {'menuIds': menuIds.join(',')}}).then((resp) => {
            if (resp.data.code === 200) {
              //删除成功后,回调更新用户数据
              this.getMenuInfo()
              this.$notify({
                title: 'Tips',
                message: '操作成功',
                type: 'success',
                duration: 2000
              })
            } else {
              this.$notify({
                title: 'Tips',
                message: '操作失败',
                type: 'error',
                duration: 2000
              })
            }
          })
        } else if (val === 'delete') {//删除用户
          this.$http.get(this.API.handleMenu + '/' + 3, {params: {'menuIds': menuIds.join(',')}}).then((resp) => {
            if (resp.data.code === 200) {
              //删除成功后,回调更新用户数据
              this.getMenuInfo()
              this.$notify({
                title: 'Tips',
                message: '操作成功',
                type: 'success',
                duration: 2000
              })
            } else {
              this.$notify({
                title: 'Tips',
                message: '操作失败',
                type: 'error',
                duration: 2000
              })
            }
          })
        }
        this.getMenuInfo()
        this.$message({
          type: 'success',
          message: '操作成功!'
        });
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消操作'
        });
      });
    },
    showAddDialog() {
      this.getTreeselect()
      this.addTableVisible = true
    },
    //点击修改按钮
    showUpdateDialog(row) {
      this.$nextTick(() => {
        this.getTreeselect()
        this.updateForm = Object.assign({}, row)
        this.updateForm.password = ''
      })
      this.updateTableVisible = true
    },
    //显示删除菜单确认框
    showDeleteMenuDialog(row) {
      if (row.children) {
        return this.$message({
          type: 'error',
          message: '请先删除所有子菜单！'
        });
      }
      const h = this.$createElement;
      this.$msgbox({
        title: '消息',
        message: h('p', null, [
          h('span', null, '是否确认删除菜单： '),
          h('i', {style: 'color: teal'}, row.menuName)
        ]),
        showCancelButton: true,
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        beforeClose: (action, instance, done) => {
          instance.confirmButtonLoading = false
          if (action === 'confirm') {
            instance.confirmButtonLoading = true;
            instance.confirmButtonText = '执行中...';
            this.$http.get(this.API.handleMenu + '/' + 3, {params: {'menuIds': row.menuId}}).then((resp) => {
              if (resp.data.code === 200) {
                //删除成功后,回调更新数据
                this.getMenuInfo()
                instance.confirmButtonLoading = false
                done()
                this.$notify({
                  title: 'Tips',
                  message: resp.data.message,
                  type: 'success',
                  duration: 2000
                })
              } else {
                this.$notify({
                  title: 'Tips',
                  message: '操作失败',
                  type: 'error',
                  duration: 2000
                })
              }
            })
          } else {
            done();
          }
        }
      }).catch(() => {
      })
    },
    //表单信息重置
    resetAddForm() {
      //清空表格数据
      this.$refs['addForm'].resetFields()
    },
    resetUpdateForm() {
      if (this.$refs['updateForm']) {
        this.$nextTick(() => {
          this.$refs['updateForm'].resetFields()
        })
      }
    },
    /** 转换菜单数据结构 */
    normalizer(node) {
      if (node.children && !node.children.length) {
        delete node.children;
      }
      let isDisabled = false;
      if (this.addTableVisible) {
        if (this.addForm.menuType == 0 || this.addForm.menuType == 1) {
          if (node.menuType != 0) {
            isDisabled = true
          }
        } else {
          if (node.menuType != 1) {
            isDisabled = true
          }
        }
      } else {
        if (this.updateForm.menuType == 0 || this.updateForm.menuType == 1) {
          if (node.menuType != 0) {
            isDisabled = true
          }
        } else {
          if (node.menuType != 1) {
            isDisabled = true
          }
        }
      }
      return {
        id: node.menuId,
        label: node.menuName,
        children: node.children,
        isDisabled: isDisabled
      };
    },
    /** 查询菜单下拉树结构 */
    getTreeselect() {
      this.menuOptions = [];
      const menu = {menuId: 0, menuName: '根目录', menuType: '0', children: []};
      menu.children = this.$store.state.menus;
      this.menuOptions.push(menu);
    },
    menuTypeChange() {
      this.addForm.menuUrl = ''
      this.addForm.component = ''
      this.addForm.menuPerms = ''
      this.addForm.icon = ''
      this.getTreeselect()
    },
    addMenu() {
      this.$refs['addForm'].validate((valid) => {
        if (valid) {
          this.$confirm("是否确认添加菜单？", '提示', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning'
          }).then(() => {
            this.$http.post(this.API.addMenu, this.addForm).then((resp) => {
              if (resp.data.code === 200) {
                this.getMenuInfo()
                this.$notify({
                  title: 'Tips',
                  message: resp.data.message,
                  type: 'success',
                  duration: 2000
                })
              } else {
                this.$notify({
                  title: 'Tips',
                  message: resp.data.message,
                  type: 'error',
                  duration: 2000
                })
              }
              this.addTableVisible = false
            })
          }).catch(() => {
            this.$message({
              type: 'info',
              message: '已取消操作'
            });
          });
        } else {
          this.$message.error('请检查您所填写的信息是否有误')
          return false
        }
      })
    },
    updateMenu() {
      this.$refs['updateForm'].validate((valid) => {
        if (valid) {
          this.$confirm("是否确认修改菜单？", '提示', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning'
          }).then(() => {
            this.$http.post(this.API.updateMenu, this.updateForm).then((resp) => {
              if (resp.data.code === 200) {
                this.getMenuInfo()
                this.$notify({
                  title: 'Tips',
                  message: resp.data.message,
                  type: 'success',
                  duration: 2000
                })
              } else {
                this.$notify({
                  title: 'Tips',
                  message: resp.data.message,
                  type: 'error',
                  duration: 2000
                })
              }
              this.updateTableVisible = false
            })
          }).catch(() => {
            this.$message({
              type: 'info',
              message: '已取消操作'
            });
          });
        } else {
          this.$message.error('请检查您所填写的信息是否有误')
          return false
        }
      })
    },
  },
}
</script>

<style scoped>
.el-container {
  width: 100%;
  height: 100%;
}

.el-input {
  width: 200px;
}

.el-container {
  animation: leftMoveIn .7s ease-in;
}

@keyframes leftMoveIn {
  0% {
    transform: translateX(-100%);
    opacity: 0;
  }
  100% {
    transform: translateX(0%);
    opacity: 1;
  }
}

.role {
  color: #606266;
}

/deep/ .el-table thead {
  color: rgb(85, 85, 85) !important;
}

/*表格的头部样式*/
/deep/ .has-gutter tr th {
  background: rgb(242, 243, 244);
  color: rgb(85, 85, 85);
  font-weight: bold;
}

.el-table {
  box-shadow: 0 0 1px 1px gainsboro;
}
</style>
